/*
    kOTF Open Trace Format - a library for generating execution traces.
    Copyright 2012 Daniel K. O.

    kOTF is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    kOTF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with kOTF.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <kotf/Session.hpp>

#include <fstream>
#include <utility>
#include <cstdlib>

#include <kotf/Stream.hpp>

#include "SessionImpl.hpp"

extern const char * __progname;

namespace kotf {

    namespace {
        bool sessionWasAutoCreated = false;
        Session* defaultSession = nullptr;
        std::once_flag defaultSessionInit;


        const char* getProgName()
        {
            return __progname;
        }

        void registerDefault(Session* s)
        {
            if (!defaultSession)
                defaultSession = s;
        }

        void unregisterDefault(Session *s)
        {
            if (defaultSession == s)
                defaultSession = nullptr;
        }

        void destroyDefault()
        {
            assert(sessionWasAutoCreated);
            delete defaultSession;
        }

        void createDefaultSession(const char * name)
        {
            if (!defaultSession) {
                sessionWasAutoCreated = true;
                defaultSession = new Session(name);
                std::atexit(destroyDefault);
            }
        }
    }


    Session::Session(const string& sessname) :
        pimpl(nullptr)
    {
        registerDefault(this);
        pimpl = new SessionImpl(this, sessname);
    }

    Session::~Session()
    {
        delete pimpl;
        unregisterDefault(this);
    }


    void
    Session::enable()
    {pimpl->enable();}
    
    void
    Session::disable()
    {pimpl->disable();}

    bool
    Session::isEnabled() const
    {return pimpl->isEnabled();}
    


    Stream&
    Session::getStream(const string& s)
    {return pimpl->getStream(s);}
    


    State
    Session::getState(uint64_t st) throw (InvalidStateId)
    {return pimpl->getState(st);}
    

    State
    Session::getState(const string& stname)
    {return pimpl->getState(stname);}


    Counter
    Session::getCounter(uint64_t cnt) throw (InvalidCounterId)
    {return pimpl->getCounter(cnt);}
    
    Counter
    Session::getCounter(const string& cntname)
    {return pimpl->getCounter(cntname);}
    


    Channel
    Session::getChannel(uint64_t ch) throw (InvalidChannelId)
    {return pimpl->getChannel(ch);}
    

    Channel
    Session::getChannel(const string& chname)
    {return pimpl->getChannel(chname);}

    

    uint64_t
    Session::getTime() const
    {
        return pimpl->getTime();
    }


    Session&
    Session::getDefault()
    {
        std::call_once(defaultSessionInit, createDefaultSession, getProgName());
        return *defaultSession;
    }

    Session&
    Session::setDefault(const string& name)
    {
        std::call_once(defaultSessionInit, createDefaultSession, name.c_str());
        Stream::setName("main");
        return *defaultSession;
    }
}

